home *** CD-ROM | disk | FTP | other *** search
/ Gamers Delight 2 / Gamers Delight 2.iso / Aminet / game / board / GNUChess4_0_58.lha / gnuchess-4.0 / src / new / book.c < prev    next >
C/C++ Source or Header  |  1992-08-26  |  9KB  |  384 lines

  1. /*
  2.  * book.c - C source for GNU CHESS
  3.  *
  4.  * Copyright (c) 1988,1989,1990 John Stanback
  5.  * Copyright (c) 1992 Free Software Foundation
  6.  *
  7.  * This file is part of GNU CHESS.
  8.  *
  9.  * GNU Chess is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2, or (at your option)
  12.  * any later version.
  13.  *
  14.  * GNU Chess is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with GNU Chess; see the file COPYING.  If not, write to
  21.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  22.  */
  23.  
  24. #include "gnuchess.h"
  25. extern char mvstr[4][6];
  26. int bookcount = 0;
  27. static struct bookentry
  28. {
  29.   unsigned long bookkey;
  30.   unsigned long bookbd;
  31.   unsigned short bmove;
  32.   unsigned short hint;
  33.   unsigned char count;
  34.   unsigned char flags;
  35. } *OpenBook;
  36. static struct bookentry *BookTable[BKTBLSIZE];
  37. void
  38. GetOpenings (void)
  39.  
  40. /*
  41.  * Read in the Opening Book file and parse the algebraic notation for a move
  42.  * into an unsigned integer format indicating the from and to square. Create
  43.  * a linked list of opening lines of play, with entry->next pointing to the
  44.  * next line and entry->move pointing to a chunk of memory containing the
  45.  * moves. More Opening lines of up to 100 half moves may be added to
  46.  * gnuchess.book.
  47.  * But now its a hashed table by position which yields a move or moves for 
  48.  * each position. It no longer knows about openings per say only positions
  49.  * and recommended moves in those positions.
  50.  */
  51. #ifndef BOOK
  52. #define BOOK "/usr/games/lib/gnuchess.book"
  53. #endif /* BOOK */
  54. {
  55.   FILE *fd;
  56.   register struct bookentry *OB, *OC;
  57.   register short int i, f, t;
  58.   char opening[80];
  59.   char msg[80];
  60.   short int xside, doit, c, side;
  61.   short int rf, rt;
  62.   unsigned short mv;
  63.   int bs;
  64.   unsigned long ltmp;
  65.   extern char *malloc();
  66.  
  67.   /* allocate space for the book */
  68.   OpenBook = (struct bookentry *) malloc(BOOKSIZE*sizeof(struct bookentry));
  69.  
  70.   for (i = 0; i < BKTBLSIZE; i++)
  71.     {
  72.       BookTable[i] = &OpenBook[BOOKSIZE / BKTBLSIZE * i];
  73.     }
  74. #ifdef BINBOOK
  75.   fd = fopen (BINBOOK, "r");
  76.   if (fd != NULL)
  77.     {
  78.       fscanf(fd, "%d\n", &bs);
  79.       fscanf(fd, "%d\n", &bookcount);
  80.       if (bs == BOOKSIZE)
  81.     {
  82.       if(0>fread(OpenBook, sizeof(struct bookentry), BOOKSIZE, fd))
  83.         perror("fread");
  84.       /* set every thing back to start game */
  85.       Book = BOOKFAIL;
  86.       for (i = 0; i < 64; i++)
  87.         {
  88.           board[i] = Stboard[i];
  89.           color[i] = Stcolor[i];
  90.         }
  91.       fclose(fd);
  92.       return;
  93.       
  94.     }
  95.       fclose(fd);
  96.     }
  97. #endif
  98.  
  99.   for (OB = OpenBook; OB < &OpenBook[BOOKSIZE]; OB++)
  100.     OB->count = 0;
  101.   if ((fd = fopen (BOOK, "r")) == NULL)
  102.     fd = fopen ("gnuchess.book", "r");
  103.   if (fd != NULL)
  104.     {
  105.       OC = NULL;
  106.       /* setvbuf(fd,buffr,_IOFBF,2048); */
  107.       side = white;
  108.       xside = black;
  109.       hashbd = hashkey = 0;
  110.       for (i = 0; i < 64; i++)
  111.     {
  112.       board[i] = Stboard[i];
  113.       color[i] = Stcolor[i];
  114.     }
  115.       i = 0;
  116.  
  117.       while ((c = parse (fd, &mv, side, opening)) >= 0)
  118.     if (c == 1)
  119.       {
  120.  
  121.         /*
  122.          * if not first move of an opening and first time we have
  123.          * seen it save next move as hint
  124.          */
  125.         if (i && OB->count == 1)
  126.           OB->hint = mv & 0x3f3f;
  127.         OC = OB;        /* save for end marking */
  128.         doit = true;
  129.  
  130.         /*
  131.          * see if this position and move already exist from some
  132.          * other opening
  133.          */
  134.         /* is this ethical, to offer the bad move as a hint????? */
  135.         for (OB = BookTable[hashkey & BOOKMASK]; OB->count; OB++)
  136.           {
  137.         if (OB->bookkey == hashkey
  138.             && OB->bookbd == hashbd
  139.             && (OB->flags & SIDEMASK) == side
  140.             && OB->bmove == mv)
  141.           {
  142.             
  143.             /*
  144.              * yes so just bump count - count is used to choose
  145.              * opening move in proportion to its presence in the
  146.              * book
  147.              */
  148.             doit = false;
  149.             OB->count++;
  150.             if (OB->count < 1)
  151.               OB->count--;
  152.             break;
  153.           }
  154.         /* Book is hashed into BKTBLSIZE chunks based on hashkey */
  155.         if (OB == &OpenBook[BOOKSIZE - 1])
  156.           OB = OpenBook;
  157.           }
  158.         /* doesn`t exist so add it to the book */
  159.         if (doit)
  160.           {
  161.         bookcount++;
  162.         OB->bookkey = hashkey;
  163.         OB->bookbd = hashbd;
  164.         OB->bmove = mv;
  165.         OB->hint = 0;
  166.         OB->count = 1;
  167.         OB->flags = side;
  168.           }
  169.         /* now update the board and hash values */
  170.         /* should really check the moves as we do this, but??? */
  171.         f = mv >> 8 & 0x3F;
  172.         t = mv & 0x3F;
  173.         if (board[t] != no_piece)
  174.           {
  175.         if (color[t] != xside)
  176.           {
  177.             algbr (f, t, false);
  178.             sprintf (msg, CP[211], i + 1, mvstr, opening);
  179.             ShowMessage (msg);
  180.           }
  181.         UpdateHashbd (xside, board[t], -1, t);
  182.           }
  183.         if (board[f] == no_piece || color[f] != side)
  184.           {
  185.         algbr (f, t, false);
  186.         sprintf (msg, CP[211], i + 1, mvstr, opening);
  187.         ShowMessage (msg);
  188.           }
  189.         UpdateHashbd (side, board[f], f, t);
  190.         board[t] = board[f];
  191.         color[t] = color[f];
  192.         color[f] = neutral;
  193.         board[f] = no_piece;
  194.         if ((board[t] == king) && ((mv == BLACKCASTLE) || (mv == WHITECASTLE) || (mv == LONGBLACKCASTLE) || (mv == LONGWHITECASTLE)))
  195.           {
  196.  
  197.         if (t > f)
  198.           {
  199.             rf = f + 3;
  200.             rt = t - 1;
  201.           }
  202.         else
  203.           {
  204.             rf = f - 4;
  205.             rt = t + 1;
  206.           }
  207.         board[rt] = rook;
  208.         color[rt] = side;
  209.         board[rf] = no_piece;
  210.         color[rf] = neutral;
  211.         UpdateHashbd (side, rook, rf, rt);
  212.           }
  213.         i++;
  214.         xside = side;
  215.         side = side ^ 1;
  216.       }
  217.     else if (c == 0 && i > 0)
  218.       {
  219.         /* Mark last move as end of an opening */
  220.         /* might want to terminate? */
  221.         OB->flags |= BOOKEND;
  222.         if (i > 1)
  223.           OC->flags |= BOOKEND;
  224.         /* reset for next opening */
  225.         side = white;
  226.         hashbd = hashkey = 0;
  227.         for (i = 0; i < 64; i++)
  228.           {
  229.         board[i] = Stboard[i];
  230.         color[i] = Stcolor[i];
  231.           }
  232.         i = 0;
  233.  
  234.       }
  235.       fclose (fd);
  236. #ifdef BINBOOK
  237.       fd = fopen (BINBOOK, "w");
  238.       fprintf(fd, "%d\n%d\n", BOOKSIZE, bookcount);
  239.       if(0>fwrite(OpenBook, sizeof(struct bookentry), BOOKSIZE, fd))
  240.     perror("fwrite");
  241.       fclose (fd);
  242. #endif
  243. #if !defined CHESSTOOL && !defined XBOARD
  244.       sprintf (msg, CP[213], bookcount, BOOKSIZE);
  245.       ShowMessage (msg);
  246. #endif
  247.       /* set every thing back to start game */
  248.       Book = BOOKFAIL;
  249.       for (i = 0; i < 64; i++)
  250.     {
  251.       board[i] = Stboard[i];
  252.       color[i] = Stcolor[i];
  253.     }
  254.     }
  255.   else
  256.     {
  257. #if !defined CHESSTOOL && !defined XBOARD
  258.       ShowMessage (CP[212]);
  259. #endif
  260.       Book = 0;
  261.     }
  262. }
  263.  
  264.  
  265. int
  266. OpeningBook (unsigned short *hint, short int side)
  267.      
  268. /*
  269.  * Go thru each of the opening lines of play and check for a match with the
  270.  * current game listing. If a match occurs, generate a random number. If this
  271.  * number is the largest generated so far then the next move in this line
  272.  * becomes the current "candidate". After all lines are checked, the
  273.  * candidate move is put at the top of the Tree[] array and will be played by
  274.  * the program. Note that the program does not handle book transpositions.
  275.  */
  276.  
  277. {
  278.   short pnt;
  279.   unsigned short m;
  280.   unsigned r, cnt, tcnt, ccnt;
  281.   register struct bookentry *OB, *OC;
  282.   int possibles = TrPnt[2] - TrPnt[1];
  283.  
  284.   srand ((unsigned int) time ((long *) 0));
  285.   m = 0;
  286.   cnt = 0;
  287.   tcnt = 0;
  288.   ccnt = 0;
  289.   OC = NULL;
  290.   
  291.  
  292.   /*
  293.    * find all the moves for this position  - count them and get their total
  294.    * count
  295.    */
  296.   for (OB = BookTable[hashkey & BOOKMASK]; OB->count; OB++)
  297.     {
  298.       if (OB->bookkey == hashkey
  299.       && OB->bookbd == hashbd
  300.       && ((OB->flags) & SIDEMASK) == side)
  301.     {
  302.       if (OB->bmove & BADMOVE)
  303.         {
  304.           m = OB->bmove ^ BADMOVE;
  305.           /* is the move is in the MoveList */
  306.           for (pnt = TrPnt[1]; pnt < TrPnt[2]; pnt++)
  307.         {
  308.           if (((Tree[pnt].f << 8) | Tree[pnt].t) == m)
  309.             {
  310.               if (--possibles)
  311.             {
  312.               Tree[pnt].score = DONTUSE;
  313.               break;
  314.             }
  315.             }
  316.         }
  317.  
  318.         }
  319.       else
  320.         {
  321.           OC = OB;
  322.           cnt++;
  323.           tcnt += OB->count;
  324.         }
  325.     }
  326.     }
  327.   /* if only one just do it */
  328.   if (cnt == 1)
  329.     {
  330.       m = OC->bmove;
  331.     }
  332.   else
  333.     /* more than one must choose one at random */
  334.   if (cnt > 1)
  335.     {
  336.       /* pick a number */
  337.       r = urand () % 1000;
  338.  
  339.       for (OC = BookTable[hashkey & BOOKMASK]; OC->count; OC++)
  340.     {
  341.       if (OC->bookkey == hashkey
  342.           && OC->bookbd == hashbd
  343.           && ((OC->flags) & SIDEMASK) == side
  344.           && !(OC->bmove & BADMOVE))
  345.         {
  346.           ccnt += OC->count;
  347.           if (((ccnt * BOOKRAND) / tcnt) >= r)
  348.         {
  349.           m = OC->bmove;
  350.           break;
  351.         }
  352.         }
  353.     }
  354.     }
  355.   else
  356.     {
  357.       /* none decrement count of no finds */
  358.       Book--;
  359.       return false;
  360.     }
  361.   /* make sure the move is in the MoveList */
  362.   for (pnt = TrPnt[1]; pnt < TrPnt[2]; pnt++)
  363.     {
  364.       if (((Tree[pnt].f << 8) | Tree[pnt].t) == m)
  365.     {
  366.       Tree[pnt].score = 0;
  367.       break;
  368.     }
  369.     }
  370.   /* Make sure its the best */
  371.  
  372.   pick (TrPnt[1], TrPnt[2] - 1);
  373.   if (Tree[TrPnt[1]].score)
  374.     {
  375.       /* no! */
  376.       Book--;
  377.       return false;
  378.     }
  379.   /* ok pick up the hint and go */
  380.   *hint = OC->hint;
  381.   Book = ((OC->flags & BOOKEND) && ((urand () % 1000) > BOOKENDPCT)) ? 0 : BOOKFAIL;
  382.   return true;
  383. }
  384.